package com.littleken.browser;

import com.littleken.core.config.SecurityProperties;
import com.littleken.core.validate.ValidateCodeFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * Security 配置类，指定Security登录验证方法
 */

@Configuration
@Slf4j
public class browserSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SecurityProperties securityProperties;//配置类

    @Autowired
    private AuthenticationSuccessHandler littlekenAuthenticationSuccessHandler;//登录成功跳转逻辑

    @Autowired
    private AuthenticationFailureHandler littlekenAuthenctiationFailureHandler;//登录失败跳转逻辑

    @Autowired
    private DataSource dataSource;//存储token的数据源

    @Autowired
    private UserDetailsService userDetailsService;

    //配置密码加密机制
    @Bean
    public PasswordEncoder passwordEncoder(){//指定密码加密
        return new BCryptPasswordEncoder();//这个加密机制每次生成的密码都不一样
    }

    @Bean
    public PersistentTokenRepository persistentTokenRepository(){
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);


        //todo:系统第一次运行时要放开注释，让他在数据库中建表，第二次运行要注释掉，不然会报 table已存在错误
        //tokenRepository.setCreateTableOnStartup(true);

        return tokenRepository;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();//初始化图片验证码过滤器
        validateCodeFilter.setAuthenticationFailureHandler(littlekenAuthenctiationFailureHandler);
        validateCodeFilter.setSecurityProperties(securityProperties);
        validateCodeFilter.afterPropertiesSet();

        http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)//在用户密码校验前，校验图片验证码
                .formLogin()//表单登录
                .loginPage("/authentication/require")//指定登录页面
                .loginProcessingUrl("/authentication/form")//加了这个才会自己跳转回请求页面
                .successHandler(littlekenAuthenticationSuccessHandler)//登录成功跳转逻辑
                .failureHandler(littlekenAuthenctiationFailureHandler)//登录失败跳转逻辑
                .and().rememberMe().tokenRepository(persistentTokenRepository())//记住登录
                .tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())//记住登录过期时间
                .userDetailsService(userDetailsService)//记住我校验
                .and().authorizeRequests()//全部都需要登录授权
                .antMatchers("/authentication/require",securityProperties.getBrowser().getLoginPage(),"/code/image").permitAll()//指定登录，图片验证码请求放行
                .anyRequest().authenticated()
                .and().csrf().disable();//关闭跨域请求验证
    }
}
